class Vue{
    constructor(options) {
        this.$el=document.querySelector(options.el);
        this.$data=options.data;
        this.$options=options;
        this.$watchEvent={}
        this.hijackData();
        this.observe();
        this.compile(this.$el);
    }
    //劫持数据
    hijackData(){
        for (let key in this.$data){
            Object.defineProperty(this,key,{
                get(){
                    return this.$data[key]
                },
                set(value){
                    this.$data[key]=value;
                }
            })
        }
    }
    observe(){
        for (let key in this.$data){
            let value=this.$data[key];
            let _this=this;
            Object.defineProperty(this.$data,key,{
                get(){
                   return value;
                },
                set(val) {
                    value=val;
                    //更新视图
                    _this.$watchEvent[key].forEach((item,index)=>{
                        item.update()
                    })
                }
            })
        }

    }
    compile(node){
      node.childNodes.forEach( (child,index)=>{
          //子节点是元素节点时候
          if (child.nodeType==1){
              if (child.hasAttribute("@click")){
                  let eventFuncName=child.getAttribute("@click");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("click",()=>{
                      this.$options.methods[eventFuncName].call(this);
                  })
              }
              if (child.hasAttribute("@dblclick")){
                  let eventFuncName=child.getAttribute("@dblclick");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("dblclick",()=>{
                      this.$options.methods[eventFuncName].call(this);
                  })
              }
              if (child.hasAttribute("@contextmenu")){
                  let eventFuncName=child.getAttribute("@contextmenu");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("contextmenu",()=>{
                      this.$options.methods[eventFuncName].call(this);
                  })
              }
              if (child.hasAttribute("@mousedown")){
                  let eventFuncName=child.getAttribute("@mousedown");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("mousedown",()=>{
                      this.$options.methods[eventFuncName].call(this);
                  })
              }
              if (child.hasAttribute("@mouseup")){
                  let eventFuncName=child.getAttribute("@mouseup");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("mouseup",()=>{
                      this.$options.methods[eventFuncName].call(this);
                  })
              }
              if (child.hasAttribute("@mouseenter")){
                  let eventFuncName=child.getAttribute("@mouseenter");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("mouseenter",()=>{
                      this.$options.methods[eventFuncName].call(this);
                  })
              }
              if (child.hasAttribute("@mouseleave")){
                  let eventFuncName=child.getAttribute("@mouseleave");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("mouseleave",()=>{
                      this.$options.methods[eventFuncName].call(this);
                  })
              }
              if (child.hasAttribute("@select")){
                  let eventFuncName=child.getAttribute("@select");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("select",(event)=>{
                      this.$options.methods[eventFuncName].call(this,event);
                  })
              }
              if (child.hasAttribute("@wheel")){
                  let eventFuncName=child.getAttribute("@wheel");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("wheel",(event)=>{
                      this.$options.methods[eventFuncName].call(this,event);
                  })
              }
              if (child.hasAttribute("@focus")){
                  let eventFuncName=child.getAttribute("@focus");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("focus",(event)=>{
                      this.$options.methods[eventFuncName].call(this,event);
                  })
              }
              if (child.hasAttribute("@blur")){
                  let eventFuncName=child.getAttribute("@blur");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("blur",(event)=>{
                      this.$options.methods[eventFuncName].call(this,event);
                  })
              }
              if (child.hasAttribute("@drag")){
                  let eventFuncName=child.getAttribute("@drag");
                  eventFuncName=eventFuncName.trim();
                  child.addEventListener("drag",(event)=>{
                      this.$options.methods[eventFuncName].call(this,event);
                  })
              }
              if (child.hasAttribute("v-model")){
                  let key=child.getAttribute("v-model");
                  key=key.trim();
                  child.value =this[key];
                  child.addEventListener("input",()=>{
                    this[key]=child.value;
                    console.log(this)
                  })
              }
              if (child.childNodes.length>0){
                  this.compile(child)
              }
          }
          // 子节点是文本节点时候
          if (child.nodeType==3){
              let reg=/\{\{(.*?)\}\}/g
              let text=child.textContent;
              child.textContent=text.replace(reg,(match,key)=>{
                  key=key.trim()
                  //给每个文本节点都添加了一个订阅者
                  let watcher=new  Watch(this,key,child,"textContent")
                  //依赖收集
                  if (this.$watchEvent[key]){
                      this.$watchEvent[key].push(watcher)
                  }else {
                      this.$watchEvent[key]=[]
                      this.$watchEvent[key].push(watcher)
                  }
                  return this.$data[key];
              })
          }
      })
    }
}


class  Watch{
    constructor(vm,key,node,attr) {
        this.vm=vm;
        this.key=key;
        this.node=node;
        this.attr=attr;
    }
    update(){
        this.node[this.attr]=this.vm[this.key];
    }
}